using System.IO;
using BomComparison.Core.Interface;
using BomComparison.Core.Model;

namespace BomComparison.Algorithm.Comparers;

public class CompareByPartNumber : IBomComparisonService
{
    public ComparisonResult CompareBoms(List<BomItem> sourceBom, List<BomItem> targetBom)
    {
        ArgumentNullException.ThrowIfNull(sourceBom);
        ArgumentNullException.ThrowIfNull(targetBom);

        var result = new ComparisonResult();

        var oldDict = CreateBomDictionary(sourceBom);
        var newDict = CreateBomDictionary(targetBom);

        var oldPartNumbers = new HashSet<string>(oldDict.Keys);
        var newPartNumbers = new HashSet<string>(newDict.Keys);

        // 1. 处理删除项
        var deletedPartNumbers = oldPartNumbers.Except(newPartNumbers).ToList();
        var deletedResults = new List<ComparisonResultByPartNumber>();
        foreach (var pn in deletedPartNumbers)
        {
            deletedResults.Add(new ComparisonResultByPartNumber
            {
                OldBomItem = oldDict[pn],
                NewBomItem = null,
                ChangedReferences = new PartReferenceDiff { Deleted = oldDict[pn].PartReference },
                ChangeType = PartNumberChangeType.Deleted
            });
        }

        // 2. 处理新增项
        var addedPartNumbers = newPartNumbers.Except(oldPartNumbers).ToList();
        var addedResults = new List<ComparisonResultByPartNumber>();
        foreach (var pn in addedPartNumbers)
        {
            addedResults.Add(new ComparisonResultByPartNumber
            {
                OldBomItem = null,
                NewBomItem = newDict[pn],
                ChangedReferences = new PartReferenceDiff { Added = newDict[pn].PartReference },
                ChangeType = PartNumberChangeType.Added
            });
        }

        // 3. 处理修改项
        var commonPartNumbers = oldPartNumbers.Intersect(newPartNumbers);
        var modifiedResults = new List<ComparisonResultByPartNumber>();
        foreach (var pn in commonPartNumbers)
        {
            var oldItem = oldDict[pn];
            var newItem = newDict[pn];
            if (!PartReferenceComparer.IsSameReference(oldItem.PartReference, newItem.PartReference)
                || oldItem.PartQuantity != newItem.PartQuantity)
            {
                modifiedResults.Add(new ComparisonResultByPartNumber
                {
                    OldBomItem = oldItem,
                    NewBomItem = newItem,
                    ChangedReferences = PartReferenceComparer.Compare(oldItem.PartReference, newItem.PartReference),
                    ChangeType = PartNumberChangeType.Modified
                });
            }
        }

        // 4. 处理替换项，保证1:1替换
        var replacements = new List<ComparisonResultByPartNumber>();
        var replacedOld = new HashSet<string>();
        var replacedNew = new HashSet<string>();
        var availableNew = new HashSet<string>(addedPartNumbers);

        foreach (var oldPn in deletedPartNumbers)
        {
            var oldItem = oldDict[oldPn];
            string matchedNewPn = null;
            foreach (var newPn in availableNew)
            {
                var newItem = newDict[newPn];
                if (PartReferenceComparer.IsSameReference(newItem.PartReference, oldItem.PartReference)
                    && newItem.PartQuantity == oldItem.PartQuantity)
                {
                    matchedNewPn = newPn;
                    break;
                }
            }
            if (matchedNewPn != null)
            {
                replacements.Add(new ComparisonResultByPartNumber
                {
                    OldBomItem = oldItem,
                    NewBomItem = newDict[matchedNewPn],
                    ChangedReferences = new PartReferenceDiff { Added = "", Deleted = "" },
                    ChangeType = PartNumberChangeType.Replaced
                });
                replacedOld.Add(oldPn);
                replacedNew.Add(matchedNewPn);
                availableNew.Remove(matchedNewPn);
            }
        }

        // 5. 过滤已被替换的新增/删除项
        deletedResults.RemoveAll(r => replacedOld.Contains(r.OldBomItem.PartNumber));
        addedResults.RemoveAll(r => replacedNew.Contains(r.NewBomItem.PartNumber));

        // 6. 合并所有结果
        result.SummaryByPartNumbers.AddRange(deletedResults);
        result.SummaryByPartNumbers.AddRange(addedResults);
        result.SummaryByPartNumbers.AddRange(modifiedResults);
        result.SummaryByPartNumbers.AddRange(replacements);

        return result;
    }

    private Dictionary<string, BomItem> CreateBomDictionary(List<BomItem> bom)
    {
        var dict = new Dictionary<string, BomItem>();
        foreach (var item in bom)
        {
            if (string.IsNullOrWhiteSpace(item.PartNumber))
                throw new InvalidDataException("存在空 PartNumber");
            if (dict.ContainsKey(item.PartNumber))
                throw new InvalidDataException($"存在重复 PartNumber: {item.PartNumber}");
            dict[item.PartNumber] = item;
        }
        return dict;
    }
}
